package com.sc.util.ChanPay.pay;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.lang.StringUtils;

import com.alibaba.fastjson.JSON;
import com.sc.util.ChanPay.util.CJTqueryTrade;
import com.sc.util.ChanPay.util.HttpProtocolHandler;
import com.sc.util.ChanPay.util.HttpRequest;
import com.sc.util.ChanPay.util.HttpResponse;
import com.sc.util.ChanPay.util.HttpResultType;
import com.sc.util.ChanPay.util.MD5;
import com.sc.util.ChanPay.util.RSA;
import com.sc.util.ChanPay.util.TR;
import com.sc.util.adapter.ConfigBeanAdapter;

/**
 * 畅捷通支付快捷网银支付工具类
 */
public class AppPay {


	/** 商户号 */
	public static final String CHANPAY_PARTNER_ID = ConfigBeanAdapter.chanpay_partner_id;


	/**快捷网银异步回调地址 */
//	public static final String notify_url =ConfigBeanAdapter.notify_url;
	
	/** 微信appid **/
	public static final String wx_appId= ConfigBeanAdapter.wx_appId;
	
	/** 支付宝appid **/
	public static final String zfb_appId= ConfigBeanAdapter.zfb_appId;
	
	 /**
     *  畅捷支付平台公钥
     */
    private static String MERCHANT_PUBLIC_KEY = ConfigBeanAdapter.merchant_public_key;
    /**
     *  商户私钥
     */
    private static String MERCHANT_PRIVATE_KEY = ConfigBeanAdapter.merchant_private_key;
    /**
     * 编码类型
     */
    private static String charset = "UTF-8";
    
    /**
     *  产品码，生产环境，测试环境固定20201
     */
    private static String product_code ="20201";
    
    /**
     * 2.7查询银行列表接口cjt_get_paychannel
     */
    public static  TR getCjtBankList() {
    	 TR tr = null;
    	 try{
    		 Map<String, String> origMap = new HashMap<String, String>();
    	        // 2.1 基本参数
    	        origMap.put("service", "cjt_get_paychannel");// 支付的接口名
    	        origMap.put("version", "1.0");
    	        origMap.put("partner_id", CHANPAY_PARTNER_ID); // 畅捷支付分配的商户号
    	        origMap.put("_input_charset", charset);// 字符集
    	        // 2.7查询银行列表接口
    	        origMap.put("product_code", product_code);// 产品码，生产环境，测试环境固定20201

    	       String s  = gatewayPost(origMap, charset, MERCHANT_PRIVATE_KEY);
    	       tr =  JSON.parseObject(s, TR.class);
    	       /*String list =  tr.getPay_inst_list();
    		   List<RS> carts =JSON.parseObject(list, new TypeReference<List<RS>>(){});  
    		   for(RS rs :carts){
    			   System.out.println("ZGYH("+"\""+ rs.getInstCode()+"\""+","+"\""+rs.getInstName()+"\"),");
    		   }*/
    	 }catch(Exception e){
    		 e.printStackTrace();
    	 }
       
         return  tr;
    }
    /**
     * 异步通知验签仅供参考 2.3单笔支付，2.18，2.19快捷支付api，对应异步通知参数见2.8 2.5退款接口，对应异步通知参数见2.9 2.14付款到卡接口，对应异步通知参数见2.15 2.20订单提现接口，对应异步通知参数见2.15
     */
    public static boolean notifyVerify(Map<String, String> paramMap) { 
    	String sign =  paramMap.get("sign").toString();
    	//paramMap.remove("sign");
        String text = createLinkString(paramMap, false);
        System.out.println("ori_text:" + text);
        try {
           return RSA.verify(text,sign, MERCHANT_PUBLIC_KEY, charset);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 2.6根据订单号查询交易接口cjt_query_trade 测试环境例子，订单一NO201607062019409608【INSTANT】订单二CJ20160715M200000017【WITHDRAWAL】 快捷支付api的也用【INSTANT】
     */
    public static CJTqueryTrade  cjt_query_trade(String outer_trade_no) {
    	CJTqueryTrade trade= null;    	
    	try{

            Map<String, String> origMap = new HashMap<String, String>();
            // 2.1 基本参数
            origMap.put("service", "cjt_query_trade");// 支付的接口名
            origMap.put("version", "1.0");
            origMap.put("partner_id", CHANPAY_PARTNER_ID); // 畅捷支付分配的商户号
            origMap.put("_input_charset", charset);// 字符集
            // 2.6查询交易接口
            origMap.put("outer_trade_no", outer_trade_no);// 这里有坑，是outer_trade_no【outer】不是out_trade_no【out】
            origMap.put("trade_type", "INSTANT");// 交易的类型类型包括 即时到账(INSTANT)，担保交易(ENSURE)， 退款(REFUND),提现（WITHDRAWAL）

            String reslult =  gatewayPost(origMap, charset, MERCHANT_PRIVATE_KEY);
            trade = JSON.parseObject(reslult, CJTqueryTrade.class);
    	}catch(Exception e){
    		e.printStackTrace();
    	}
        return trade ;
    }
    
    /**
     * 2.18快捷支付api cjt_quick_payment 商户通过API接口方式实现单笔订单快捷支付。
     */
    public static String  createQPay(Map<String, String> origMap ,String notify_url) {
        // 2.1 基本参数
        origMap.put("version", "1.0");
        origMap.put("partner_id", CHANPAY_PARTNER_ID); // 畅捷支付分配的商户号
        origMap.put("_input_charset", charset);// 字符集
        origMap.put("service", "cjt_quick_payment");// 支付的接口名
        origMap.put("out_trade_no",origMap.get("out_trade_no").toString());// 订单号
        origMap.put("trade_amount", origMap.get("trade_amount").toString());// 金额
        //origMap.put("is_anonymous", "Y");// 是否匿名 必须写Y，然后buyer,seller相关的参数不要填写，因为写N的话，要求买家（商户那边，来付款的普通用户）也是畅捷的用户
        //origMap.put("sell_id", CHANPAY_PARTNER_ID); //卖家标示ID   //
        //   origMap.put("buyer_id_type","MEMBER_ID" );//买家ID类型
        origMap.put("buyer_ip",origMap.get("buyer_ip").toString());//	买家ID
       // origMap.put("buyer_mobile", phone);//买家手机号   			    //
       // origMap.put("buyer_id_type","MEMBER_ID" );//买家ID类型
       // origMap.put("return_url", origMap.get("return_url").toString());//处理完请求后，当前页面自动跳转到商户网站里指定页面的http路径。 空则不会进行该操作。
       // 2.18快捷支付api 业务参数
       //  String out_trade_no = (UUID.randomUUID().toString()).replace("-", "");
       // 2.18快捷支付api 支付相关参数
        origMap.put("card_type", "DC");//卡类型
        origMap.put("pay_type", "C");//对公对私
        origMap.put("bank_code", origMap.get("bank_code").toString());//银行编码
        origMap.put("expiry_date", encrypt("00/00", MERCHANT_PUBLIC_KEY, charset));
        origMap.put("payer_name", encrypt(origMap.get("payer_name").toString(), MERCHANT_PUBLIC_KEY, charset));//付款方名称
        origMap.put("payer_card_no", encrypt(origMap.get("payer_card_no").toString(), MERCHANT_PUBLIC_KEY, charset));//付款方银行卡号
        origMap.put("id_number", encrypt(origMap.get("id_number").toString(), MERCHANT_PUBLIC_KEY, charset));//身份证号
        origMap.put("phone_number", encrypt(origMap.get("phone_number").toString(), MERCHANT_PUBLIC_KEY, charset));//手机号
        origMap.put("notify_url", notify_url);// 前台跳转url
        return gatewayPost(origMap, charset, MERCHANT_PRIVATE_KEY);
    	
    }

    /**
     * 2.19快捷api确认 cjt_quick_payment_confirm
     */
    public static String  createQPayConfirm(String out_trade_no,String verification_code ) {

        Map<String, String> origMap = new HashMap<String, String>();
        // 2.1 基本参数
        origMap.put("version", "1.0");
        origMap.put("partner_id", CHANPAY_PARTNER_ID); // 畅捷支付分配的商户号
        origMap.put("_input_charset", charset);// 字符集
        origMap.put("service", "cjt_quick_payment_confirm");// 支付的接口名
        // 2.19快捷api确认
        origMap.put("out_trade_no", out_trade_no);// 订单号
        origMap.put("verification_code", verification_code);// 短信验证码

        return gatewayPost(origMap, charset, MERCHANT_PRIVATE_KEY);
    }


    /**
     * 2.3微信app支付
     */
    /**
	 * @Title: wxAppPay
	 * @Description  畅捷通微信app支付接口2.3
	 * @param out_trade_no  //商品订单号
	 * @param trade_amount  //订单交易金额单位元
	 * @param return_url
	 * @date 2017年3月13日上午11:55:35
	 * @author LeiJia  
	 * @return 
	 */
    public static String wxAppPay(String out_trade_no,String trade_amount, String return_url,String notify_url){
    	  Map<String, String> origMap = new HashMap<String, String>();
          // 2.1 基本参数
          origMap.put("version", "1.0");
          origMap.put("partner_id", CHANPAY_PARTNER_ID); // 畅捷支付分配的商户号
          origMap.put("_input_charset", charset);// 字符集 UTF-8
          origMap.put("is_anonymous", "Y");// 是否匿名 必须写Y，然后buyer,seller相关的参数不要填写，因为写N的话，要求买家（商户那边，来付款的普通用户）也是畅捷的用户
          origMap.put("return_url", return_url);//处理完请求后，当前页面自动跳转到商户网站里指定页面的http路径。 空则不会进行该操作。
          // 2.3 单笔支付
         //  String out_trade_no = (UUID.randomUUID().toString()).replace("-", "");
          System.out.println(out_trade_no);
          origMap.put("out_trade_no", out_trade_no);// 订单号
          origMap.put("pay_method", "1");// 含义看文档 收银台写2 直连网银1
          origMap.put("pay_type", "C,GC");// 含义看文档 连收银台此值为空
          origMap.put("bank_code", "WXPAY");// 含义看文档 跳收银台此值为空，不要再写TESTBANK了
          origMap.put("is_returnpayurl ", "N");// 前台跳转url 扫码支付必传	Y：需要返回扫码支付付款二维码URL地址； N：不同步返回（默认
          origMap.put("service", "cjt_create_instant_trade");// 支付的接口名
          //origMap.put("trade_amount", "10.00");// 金额
          origMap.put("trade_amount", trade_amount);
          origMap.put("notify_url", notify_url);// 前台跳转url
          origMap.put("ext1", "[{'offLinePay':'ANDROID '}]");
          return gatewayPost(origMap, charset, MERCHANT_PRIVATE_KEY);
    
    }
	/**
	 * 获取SimpleDateFormat
	 * 
	 * @param parttern
	 *            日期格式
	 * @return SimpleDateFormat对象
	 * @throws RuntimeException
	 *             异常：非法日期格式
	 */
	private static SimpleDateFormat getDateFormat(String parttern)
			throws RuntimeException {
		return new SimpleDateFormat(parttern);
	}
    /**
     * 建立请求，以模拟远程HTTP的POST请求方式构造并获取钱包的处理结果 如果接口中没有上传文件参数，那么strParaFileName与strFilePath设置为空值 如：buildRequest("", "",sParaTemp)
     *
     * @param strParaFileName
     *            文件类型的参数名
     * @param strFilePath
     *            文件路径
     * @param sParaTemp
     *            请求参数数组
     * @return 钱包处理结果
     * @throws Exception
     */
    public static String buildRequest(Map<String, String> sParaTemp, String signType, String key, String inputCharset, String gatewayUrl) throws Exception {
        // 待请求参数数组
        Map<String, String> sPara = buildRequestPara(sParaTemp, signType, key, inputCharset);
        HttpProtocolHandler httpProtocolHandler = HttpProtocolHandler.getInstance();
        HttpRequest request = new HttpRequest(HttpResultType.BYTES);
        // 设置编码集
        request.setCharset(inputCharset);
        request.setMethod(HttpRequest.METHOD_POST);
        request.setParameters(generatNameValuePair(createLinkRequestParas(sPara), inputCharset));
        request.setUrl(gatewayUrl);
        HttpResponse response = httpProtocolHandler.execute(request, null, null);
        if (response == null) {
            return null;
        }
        String strResult = response.getStringResult();
        return strResult;
    }

    /**
     * MAP类型数组转换成NameValuePair类型
     *
     * @param properties
     *            MAP类型数组
     * @return NameValuePair类型数组
     */
    private static NameValuePair[] generatNameValuePair(Map<String, String> properties, String charset) throws Exception {
        NameValuePair[] nameValuePair = new NameValuePair[properties.size()];
        int i = 0;
        for (Map.Entry<String, String> entry : properties.entrySet()) {
            // nameValuePair[i++] = new NameValuePair(entry.getKey(), URLEncoder.encode(entry.getValue(),charset));
            nameValuePair[i++] = new NameValuePair(entry.getKey(), entry.getValue());
        }
        return nameValuePair;
    }

    /**
     * 生成要请求给钱包的参数数组
     * 
     * @param sParaTemp
     *            请求前的参数数组
     * @param signType
     *            RSA
     * @param key
     *            商户自己生成的商户私钥
     * @param inputCharset
     *            UTF-8
     * @return 要请求的参数数组
     * @throws Exception
     */
    public static Map<String, String> buildRequestPara(Map<String, String> sParaTemp, String signType, String key, String inputCharset) throws Exception {
        // 除去数组中的空值和签名参数
        Map<String, String> sPara = paraFilter(sParaTemp);
        // 生成签名结果
        String mysign = "";
        if ("MD5".equalsIgnoreCase(signType)) {
            mysign = buildRequestByMD5(sPara, key, inputCharset);
        } else if ("RSA".equalsIgnoreCase(signType)) {
            mysign = buildRequestByRSA(sPara, key, inputCharset);
        }
        // 签名结果与签名方式加入请求提交参数组中
        System.out.println("sign:" + mysign);
        sPara.put("sign", mysign);
        sPara.put("sign_type", signType);

        return sPara;
    }

    /**
     * 生成MD5签名结果
     *
     * @param sPara
     *            要签名的数组
     * @return 签名结果字符串
     */
    public static String buildRequestByMD5(Map<String, String> sPara, String key, String inputCharset) throws Exception {
        String prestr = createLinkString(sPara, false); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
        String mysign = "";
        mysign = MD5.sign(prestr, key, inputCharset);
        return mysign;
    }

    /**
     * 生成RSA签名结果
     *
     * @param sPara
     *            要签名的数组
     * @return 签名结果字符串
     */
    public static String buildRequestByRSA(Map<String, String> sPara, String privateKey, String inputCharset) throws Exception {
        String prestr = createLinkString(sPara, false); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
        String mysign = "";
        mysign = RSA.sign(prestr, privateKey, inputCharset);
        return mysign;
    }

    /**
     * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
     *
     * @param params
     *            需要排序并参与字符拼接的参数组
     * @param encode
     *            是否需要urlEncode
     * @return 拼接后字符串
     */
    public static Map<String, String> createLinkRequestParas(Map<String, String> params) {
        Map<String, String> encodeParamsValueMap = new HashMap<String, String>();
        List<String> keys = new ArrayList<String>(params.keySet());
        String charset = params.get("_input_charset");
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value;
            try {
                value = URLEncoder.encode(params.get(key), charset);
                encodeParamsValueMap.put(key, value);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }

        return encodeParamsValueMap;
    }

    /**
     * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
     *
     * @param params
     *            需要排序并参与字符拼接的参数组
     * @param encode
     *            是否需要urlEncode
     * @return 拼接后字符串
     */
    public static String createLinkString(Map<String, String> params, boolean encode) {

        // params = paraFilter(params);

        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);

        String prestr = "";

        String charset = params.get("_input_charset");
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            if (encode) {
                try {
                    value = URLEncoder.encode(value, charset);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }

            if (i == keys.size() - 1) {// 拼接时，不包括最后一个&字符
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }

        return prestr;
    }

    /**
     * 除去数组中的空值和签名参数
     *
     * @param sArray
     *            签名参数组
     * @return 去掉空值与签名参数后的新签名参数组
     */
    public static Map<String, String> paraFilter(Map<String, String> sArray) {

        Map<String, String> result = new HashMap<String, String>();

        if (sArray == null || sArray.size() <= 0) {
            return result;
        }

        for (String key : sArray.keySet()) {
            String value = sArray.get(key);
            if (value == null || value.equals("") || key.equalsIgnoreCase("sign") || key.equalsIgnoreCase("sign_type")) {
                continue;
            }
            // try {
            // value = URLEncoder.encode(value,charset);
            // } catch (UnsupportedEncodingException e) {
            // e.printStackTrace();
            // }
            result.put(key, value);
        }

        return result;
    }

    /**
     * 向测试服务器发送post请求
     * 
     * @param origMap
     *            参数map
     * @param charset
     *            编码字符集
     * @param MERCHANT_PRIVATE_KEY
     *            私钥
     */
    public static  String gatewayPost(Map<String, String> origMap, String charset, String MERCHANT_PRIVATE_KEY) {
    	String resultString="";
    	try {
            String urlStr = ConfigBeanAdapter.gatewayPost;
            Map<String, String> sPara = buildRequestPara(origMap, "RSA", MERCHANT_PRIVATE_KEY, charset);
            System.out.println(urlStr + createLinkString(sPara, true));
            resultString = buildRequest(origMap, "RSA", MERCHANT_PRIVATE_KEY, charset, urlStr);
            System.out.println(resultString);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultString;
    }

    /**
     * 加密，2.14付款到卡接口等部分接口，有参数需要加密
     * 
     * @param src
     *            原值
     * @param publicKey
     *            畅捷支付发送的平台公钥
     * @param charset
     *            UTF-8
     * @return RSA加密后的密文
     */
    private static String encrypt(String src, String publicKey, String charset) {
        try {
            byte[] bytes = RSA.encryptByPublicKey(src.getBytes(charset), publicKey);
            return Base64.encodeBase64String(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**
	 * 扫码支付服务器发送post请求
	 * 
	 * @param origMap
	 *            参数map
	 * @param charset
	 *            编码字符集
	 * @param MERCHANT_PRIVATE_KEY
	 *            私钥
	 */
	public static String sweepGatewayPost(Map<String, String> origMap, String charset,
			String MERCHANT_PRIVATE_KEY) {
		String resultString ="";
		try {
			String urlStr = ConfigBeanAdapter.gatewayPost;
			Map<String, String> sPara = buildSweepRequestPara(origMap, "RSA",
					MERCHANT_PRIVATE_KEY, charset);
			System.out.println(urlStr + createSweepLinkString(sPara, true));
		    resultString = buildSweepRequest(origMap, "RSA",
					MERCHANT_PRIVATE_KEY, charset, urlStr);
			System.out.println(resultString);
		} catch (Exception e) {
			System.out.println(e);
		}
		return resultString;
	}
	/**
	 * 生成要请求给钱包的参数数组
	 * 
	 * @param sParaTemp
	 *            请求前的参数数组
	 * @param signType
	 *            RSA
	 * @param key
	 *            商户自己生成的商户私钥
	 * @param inputCharset
	 *            UTF-8
	 * @return 要请求的参数数组
	 * @throws Exception
	 */
	public static Map<String, String> buildSweepRequestPara(
			Map<String, String> sParaTemp, String signType, String key,
			String inputCharset) throws Exception {
		// 除去数组中的空值和签名参数
		Map<String, String> sPara = paraFilter(sParaTemp);
		// 生成签名结果
		String mysign = "";
		if ("MD5".equalsIgnoreCase(signType)) {
			mysign = buildRequestByMD5(sPara, key, inputCharset);
		} else if ("RSA".equalsIgnoreCase(signType)) {
			mysign = buildRequestByRSA(sPara, key, inputCharset);
		}
		// 签名结果与签名方式加入请求提交参数组中
		System.out.println("sign:" + mysign);
		sPara.put("Sign", mysign);
		sPara.put("SignType", signType);

		return sPara;
	}
	/**
	 * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
	 *
	 * @param params
	 *            需要排序并参与字符拼接的参数组
	 * @param encode
	 *            是否需要urlEncode
	 * @return 拼接后字符串
	 */
	public static String createSweepLinkString(Map<String, String> params,
			boolean encode) {

		// params = paraFilter(params);

		List<String> keys = new ArrayList<String>(params.keySet());
		Collections.sort(keys);

		String prestr = "";

		String charset = params.get("Charset");
		if (StringUtils.isBlank(charset)) {
			charset = params.get("InputCharset");
		}

		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			String value = params.get(key);
			if (encode) {
				try {
					value = URLEncoder.encode(value, charset);
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			}

			if (i == keys.size() - 1) {// 拼接时，不包括最后一个&字符
				prestr = prestr + key + "=" + value;
			} else {
				prestr = prestr + key + "=" + value + "&";
			}
		}

		return prestr;
	}
	
	/**
	 * 建立请求，以模拟远程HTTP的POST请求方式构造并获取钱包的处理结果
	 * 如果接口中没有上传文件参数，那么strParaFileName与strFilePath设置为空值 如：buildRequest("",
	 * "",sParaTemp)
	 *
	 * @param strParaFileName
	 *            文件类型的参数名
	 * @param strFilePath
	 *            文件路径
	 * @param sParaTemp
	 *            请求参数数组
	 * @return 钱包处理结果
	 * @throws Exception
	 */
	public static String buildSweepRequest(Map<String, String> sParaTemp,
			String signType, String key, String inputCharset, String gatewayUrl)
			throws Exception {
		// 待请求参数数组
		Map<String, String> sPara = buildRequestPara(sParaTemp, signType, key,
				inputCharset);
		HttpProtocolHandler httpProtocolHandler = HttpProtocolHandler
				.getInstance();
		HttpRequest request = new HttpRequest(HttpResultType.BYTES);
		// 设置编码集
		request.setCharset(inputCharset);
		request.setMethod(HttpRequest.METHOD_POST);
		request.setParameters(generatNameValuePair(
				createLinkRequestParas(sPara), inputCharset));
		request.setUrl(gatewayUrl);
		HttpResponse response = httpProtocolHandler
				.execute(request, null, null);
		if (response == null) {
			return null;
		}
		String strResult = response.getStringResult();
		return strResult;
	}
}
